#include "pch.h"

#include "threading/win32/win32thread.h"



namespace Win32
{
	RE_ImplementClass('WTHD', Win32::Win32Thread, Core::ReferenceCount);


	ThreadLocal const char * Win32Thread::ThreadName = 0;



	///
	Win32Thread::Win32Thread():
	m_threadHandle(0),
		m_priority(Normal),
		m_stackSize(16384),
		m_coreID(System::CPU::InvalidCoreID)
	{

	}


	///
	Win32Thread::~Win32Thread()
	{
		if(this->IsRunning())
		{
			this->Stop();
		}
	}


	///
	void Win32Thread::Start()
	{
		this->m_threadHandle = CreateThread(NULL,
			this->m_stackSize,
			ThreadProc,
			(LPVOID)this,
			CREATE_SUSPENDED,
			NULL);

		switch(this->m_priority)
		{
		case VeryLow:
			SetThreadPriority(this->m_threadHandle, THREAD_PRIORITY_LOWEST);
			break;
		case Low:
			SetThreadPriority(this->m_threadHandle, THREAD_PRIORITY_BELOW_NORMAL);
			break;
		case Normal:
			SetThreadPriority(this->m_threadHandle, THREAD_PRIORITY_NORMAL);
			break;
		case High:
			SetThreadPriority(this->m_threadHandle, THREAD_PRIORITY_ABOVE_NORMAL);
			break;
		case VeryHigh:
			SetThreadPriority(this->m_threadHandle, THREAD_PRIORITY_HIGHEST);
			break;
		}


		ResumeThread(this->m_threadHandle);

		this->m_startEvent.Wait();
	}



	///
	void Win32Thread::EmitWakeupSignal()
	{

	}


	///
	void Win32Thread::Stop()
	{
		this->m_stopEvent.Signal();

		this->EmitWakeupSignal();

		WaitForSingleObject(this->m_threadHandle, INFINITE);

		CloseHandle(this->m_threadHandle);

		this->m_threadHandle = 0;
	}


	///
	bool Win32Thread::IsRunning() const 
	{
		if(0 != this->m_threadHandle)
		{
			DWORD exit = 0;

			if(GetExitCodeThread(this->m_threadHandle, &exit))
			{
				if(STILL_ACTIVE == exit)
				{
					return true;
				}
			}
		}

		return false;
	}


	///
	void Win32Thread::DoWork()
	{

	}


	///
	DWORD WINAPI Win32Thread::ThreadProc(LPVOID self)
	{
		//Helper::LocalStringAtomTable m_locStr;

		Win32Thread * thrdObj = (Win32Thread*)self;

		Win32Thread::SetMyThreadName(thrdObj->GetNameOfClass().GetAsCharPtr());

		thrdObj->m_startEvent.Signal();

		thrdObj->DoWork();

		return 0;
	}



	///
	void Win32Thread::SetMyThreadName(const char * name)
	{
		ThreadName = name;

		struct THREADNAME_INFO
		{
			DWORD dwType;
			LPCSTR szName;
			DWORD dwThreadID;
			DWORD dwFlags;
		};


		THREADNAME_INFO info;

		info.dwType = 0x1000;
		info.szName = name;
		info.dwThreadID = ::GetCurrentThreadId();
		info.dwFlags = 0;

		__try
		{
			RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (DWORD*)&info);
		}

		__except(EXCEPTION_CONTINUE_EXECUTION)
		{
		}
	}


	///
	const char * Win32Thread::GetMyThreadName() 
	{
		return ThreadName;
	}


	///
	Threading::ThreadID Win32Thread::GetMyThreadID() 
	{
		return ::GetCurrentThreadId();
	}


	///
	void Win32Thread::YieldThread()
	{

	}





	///
	void Win32Thread::SetPriority(Win32::Win32Thread::Priority pri)
	{
		this->m_priority = pri;
	}


	///
	void Win32Thread::SetStackSize(tSize size)
	{
		this->m_stackSize = size;
	}


	///
	void Win32Thread::SetCoreID(System::CPU::CoreID id)
	{
		this->m_coreID = id;
	}


	///
	void Win32Thread::SetName(const Helper::String &name)
	{
		this->m_name = name;
	}


	///
	Win32Thread::Priority Win32Thread::GetPriority() const
	{
		return this->m_priority;
	}


	///
	tSize Win32Thread::GetStackSize() const
	{
		return this->m_stackSize;
	}


	///
	const Helper::String & Win32Thread::GetName() const 
	{
		return this->m_name;
	}


	///
	System::CPU::CoreID Win32Thread::GetCoreID() const
	{
		return this->m_coreID;
	}


	///
	bool Win32Thread::ThreadStopRequested() const
	{
		return this->m_stopEvent.Peek();
	}


}